package io.kiki.sba.registry.server.data_store.pubiterator;


import io.kiki.sba.registry.common.model.RegisterVersion;
import io.kiki.sba.registry.common.model.dataserver.DatumSummary;
import io.kiki.sba.registry.common.model.slot.filter.SyncAcceptorRequest;
import io.kiki.sba.registry.common.model.slot.filter.SyncSlotAcceptorManager;
import io.kiki.sba.registry.server.data_store.cache.PublisherEnvelope;
import io.kiki.sba.registry.server.data_store.cache.PublisherGroup;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BiConsumer;


public class DatumBiConsumer {

    public static BiConsumer<String, PublisherGroup> publisherGroupsBiConsumer(Map<String, Map<String, DatumSummary>> summaries, Set<String> sessions, SyncSlotAcceptorManager syncSlotAcceptorManager) {
        for (String sessionIp : sessions) {
            summaries.computeIfAbsent(sessionIp, v -> new HashMap<>(64));
        }

        return (dataInfoId, publisherGroup) -> {
            Map<String /*sessionIp*/, Map<String /*registerId*/, RegisterVersion>> publisherVersions = new HashMap<>(sessions.size());

            if (!syncSlotAcceptorManager.accept(SyncAcceptorRequest.buildRequest(dataInfoId))) {
                return;
            }

            publisherGroup.foreach(publisherGroupBiConsumer(dataInfoId, publisherVersions, sessions, syncSlotAcceptorManager));
            Map<String, DatumSummary> map = new HashMap<>(sessions.size());

            for (Entry<String, Map<String, RegisterVersion>> entry : publisherVersions.entrySet()) {
                map.put(entry.getKey(), new DatumSummary(dataInfoId, entry.getValue()));
            }

            for (Entry<String, DatumSummary> entry : map.entrySet()) {
                if (entry.getValue().isEmpty()) {
                    continue;
                }
                Map<String, DatumSummary> summaryMap = summaries.get(entry.getKey());
                summaryMap.put(dataInfoId, entry.getValue());
            }
        };
    }

    public static BiConsumer<String, PublisherEnvelope> publisherGroupBiConsumer(String dataInfoId, Map<String, Map<String, RegisterVersion>> publisherVersions, Set<String> sessions, SyncSlotAcceptorManager syncSlotAcceptorManager) {

        for (String clientInterfaceNodeIp : sessions) {
            publisherVersions.computeIfAbsent(clientInterfaceNodeIp, k -> new HashMap<>(64));
        }

        return (registerId, publisherEnvelope) -> {
            RegisterVersion registerVersion = publisherEnvelope.getVersionIfPub();
            // v = null when envelope is unpub
            if (registerVersion == null || !syncSlotAcceptorManager.accept(SyncAcceptorRequest.buildRequest(dataInfoId, publisherEnvelope.getPublisher().getPublishSource()))) {
                return;
            }

            if (sessions.contains(publisherEnvelope.getClientInterfaceId().getHostAddress())) {
                publisherVersions.get(publisherEnvelope.getClientInterfaceId().getHostAddress()).put(registerId, registerVersion);
            }
        };
    }

    public static BiConsumer<String, PublisherGroup> publisherGroupsBiConsumer(Map<String, DatumSummary> summaries, SyncSlotAcceptorManager syncSlotAcceptorManager) {
        return (dataInfoId, publisherGroup) -> {
            if (!syncSlotAcceptorManager.accept(SyncAcceptorRequest.buildRequest(dataInfoId))) {
                return;
            }

            Map<String /*registerId*/, RegisterVersion> map = new HashMap<>(publisherGroup.pubSize());
            publisherGroup.foreach(publisherGroupBiConsumer(dataInfoId, map, syncSlotAcceptorManager));
            DatumSummary datumSummary = new DatumSummary(dataInfoId, map);
            summaries.put(dataInfoId, datumSummary);
        };
    }

    public static BiConsumer<String, PublisherEnvelope> publisherGroupBiConsumer(String dataInfoId, Map<String, RegisterVersion> publisherVersions, SyncSlotAcceptorManager syncSlotAcceptorManager) {
        return (registerId, publisherEnvelope) -> {
            RegisterVersion registerVersion = publisherEnvelope.getVersionIfPub();
            // v = null when envelope is unpub
            if (registerVersion == null || !syncSlotAcceptorManager.accept(SyncAcceptorRequest.buildRequest(dataInfoId, publisherEnvelope.getPublisher().getPublishSource()))) {
                return;
            }
            publisherVersions.put(registerId, registerVersion);
        };
    }
}
